package helper

// groupFunc 条件过滤函数
// current 当前记录, last 上一条记录
func groupFunc(current, last map[string]interface{}, groupBy []string) bool {
	for _, k := range groupBy {
		if last == nil {
			return false
		}

		switch v1 := current[k].(type) {
		case []uint8:
			v2 := last[k].([]uint8)

			if string(v1) != string(v2) {
				return false
			}
		default:

			if current[k] != last[k] {
				return false
			}
		}
	}

	return true
}

// inSlice 是否在 slice 中
func inSlice(s []string, t string) int {
	for inx, v := range s {
		if t == v {
			return inx
		}
	}

	return -1
}

// pick 从 map 中取出指定的字段组成新map
func pick(src map[string]interface{}, fields []string) (map[string]interface{}, map[string]interface{}) {
	has := make(map[string]interface{})
	left := make(map[string]interface{})

	for k, v := range src {
		if inSlice(fields, k) > -1 {
			has[k] = v
		} else {
			left[k] = v
		}
	}

	return has, left
}

// MapSliceExtract 从 Map-Slice 中抽取一个key对应的所有值
func MapSliceExtract(ms []map[string]interface{}, key string) []interface{} {
	res := make([]interface{}, 0)

	for _, mp := range ms {
		if v, ok := mp[key]; ok {
			res = append(res, v)
		}
	}

	return res
}

// MapSliceGroupBy 将 Map-Slice ms 按照 groupBy 拆分
func MapSliceGroupBy(ms []map[string]interface{}, groupBy []string, toField ...string) []map[string]interface{} {
	var fieldsLeft string
	if len(toField) > 0 {
		fieldsLeft = toField[0]
	}

	res := make([]map[string]interface{}, 0)

	var item map[string]interface{}
	var last map[string]interface{}
	for _, row := range ms {
		// 如果是重复记录
		if groupFunc(row, last, groupBy) {
			if fieldsLeft != "" {
				_, left := pick(row, groupBy)
				itemLeft := item[fieldsLeft].([]map[string]interface{})
				itemLeft = append(itemLeft, left)
				item[fieldsLeft] = itemLeft
			}

			// 如果不是
		} else {
			// 是否需要放入到返回值列表
			if len(res) > 0 {
				res = append(res, item)
			}

			has, left := pick(row, groupBy)
			item = has

			if fieldsLeft != "" {
				itemLeft := []map[string]interface{}{left}
				item[fieldsLeft] = itemLeft
			}
		}

		last = row
	}

	if item != nil {
		res = append(res, item)
	}

	return res
}
